package com.yohu.blue.car;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.gcssloop.widget.RockerView;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class CarControllerActivity extends Activity {

    private final static String TAG = CarControllerActivity.class.getSimpleName();
    private BluetoothAdapter mBluetoothAdapter;

    private static final int REQUEST_ENABLE_BT = 1;

    private boolean mScanning;
    private Handler mHandler;
    private String mDeviceAddress;
    // Stops scanning after 10 seconds.
    private static final long SCAN_PERIOD = 10000;
    /**
     * 摇杆
     */
    private RockerView rocker;

    private Button btnSpeedup;
    private Button btnSlowdown;

    private BluetoothLeService mBluetoothLeService;
    // Code to manage Service lifecycle.
    private final ServiceConnection mServiceConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
            if (!mBluetoothLeService.initialize()) {
                Log.e(TAG, "Unable to initialize Bluetooth");
                finish();
            }
            // Automatically connects to the device upon successful start-up initialization.
            mBluetoothLeService.connect(mDeviceAddress);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mBluetoothLeService = null;
        }
    };

    private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
//                mConnected = true;
//                updateConnectionState(R.string.connected);
                updateStatus(true);
                invalidateOptionsMenu();
            } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
//                mConnected = false;
//                updateConnectionState(R.string.disconnected);c   vvcvv	sscom	sscom	sscom
                updateStatus(false);
                invalidateOptionsMenu();
                scanLeDevice(true);
//                clearUI();
            } else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
                // Show all the supported services and characteristics on the user interface.
                displayGattServices(context, mBluetoothLeService.getSupportedGattServices());
            } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
//                displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
            }
        }
    };
    private TextView tvStatus;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_car_controller);
        mHandler = new Handler();

        final BluetoothManager bluetoothManager =
                (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = bluetoothManager.getAdapter();
        // Checks if Bluetooth is supported on the device.
        if (mBluetoothAdapter == null) {
            Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
            finish();
            return;
        }
        btnSlowdown = findViewById(R.id.slowdown);
        btnSpeedup = findViewById(R.id.speedup);

        btnSpeedup.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                BluetoothHelper.write("k");
            }
        });

        btnSlowdown.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                BluetoothHelper.write("j");
            }
        });

        getGameControllerIds();
    }

    // Device scan callback.
    private BluetoothAdapter.LeScanCallback mLeScanCallback =
            new BluetoothAdapter.LeScanCallback() {

                @Override
                public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public synchronized void run() {
                            System.out.println("device{name=" + device.getName() + ";addr=" + device.getAddress() + "}");
                            if (device.getAddress().equalsIgnoreCase("00:15:83:00:84:DB")) {
                                mScanning = false;
                                mBluetoothAdapter.stopLeScan(mLeScanCallback);
                                invalidateOptionsMenu();

                                mDeviceAddress = device.getAddress();

                                Intent gattServiceIntent = new Intent(CarControllerActivity.this, BluetoothLeService.class);
                                bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);

                                registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
                                if (mBluetoothLeService != null) {
                                    final boolean result = mBluetoothLeService.connect(mDeviceAddress);
                                    Log.d(TAG, "Connect request result=" + result);
                                }

                            }
                        }
                    });
                }
            };

    private void scanLeDevice(final boolean enable) {
        if (enable) {
            // Stops scanning after a pre-defined scan period.
//            mHandler.postDelayed(new Runnable() {
//                @Override
//                public void run() {
//                    if (mScanning) {
//                        mScanning = false;
//                        mBluetoothAdapter.stopLeScan(mLeScanCallback);
//                        invalidateOptionsMenu();
//                    }
//                }
//            }, SCAN_PERIOD);
            mScanning = true;
            mBluetoothAdapter.startLeScan(mLeScanCallback);
        } else {
            mScanning = false;
            mBluetoothAdapter.stopLeScan(mLeScanCallback);
        }
        invalidateOptionsMenu();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        // User chose not to enable Bluetooth.
        if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) {
            finish();
            return;
        }
        super.onActivityResult(requestCode, resultCode, data);
    }

    // Demonstrates how to iterate through the supported GATT Services/Characteristics.
    // In this sample, we populate the data structure that is bound to the ExpandableListView
    // on the UI.
    private void displayGattServices(Context context, List<BluetoothGattService> gattServices) {
        if (gattServices == null) return;
        String uuid = null;

        // Loops through available GATT Services.
        for (BluetoothGattService gattService : gattServices) {
//            HashMap<String, String> currentServiceData = new HashMap<String, String>();
            uuid = gattService.getUuid().toString();
            if (!uuid.equals("0000ffe0-0000-1000-8000-00805f9b34fb")) {
                continue;
            }
            List<BluetoothGattCharacteristic> gattCharacteristics =
                    gattService.getCharacteristics();
//            ArrayList<BluetoothGattCharacteristic> charas =
//                    new ArrayList<BluetoothGattCharacteristic>();

            // Loops through available Characteristics.
            for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
                uuid = gattCharacteristic.getUuid().toString();
                if (uuid.equals("0000ffe1-0000-1000-8000-00805f9b34fb")) {
                    BluetoothHelper.getInstance(mBluetoothLeService, gattCharacteristic);
                    updateStatus(true);
//                    Intent intent = new Intent(context, CarControllerActivity.class);
//                    startActivity(intent);
                }
            }
        }

    }

    private static IntentFilter makeGattUpdateIntentFilter() {
        final IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
        intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
        intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
        intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);
        return intentFilter;
    }

    private void updateStatus(boolean isconnected) {
        if (isconnected) {
            tvStatus.setText(R.string.connected);
            tvStatus.setTextColor(Color.GREEN);
        } else {
            tvStatus.setText(R.string.disconnected);
            tvStatus.setTextColor(Color.RED);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        //判断蓝牙是否开启
        if (!mBluetoothAdapter.isEnabled()) {
            if (!mBluetoothAdapter.isEnabled()) {
                Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
            }
        }

        scanLeDevice(true);
        if (getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        }
        rocker = findViewById(R.id.rocker);
        tvStatus = findViewById(R.id.tv_status);

        if (null != rocker) {
            rocker.setListener(new RockerView.RockerListener() {
                @Override
                public void callback(int eventType, int currentAngle, float currentDistance) {
                    switch (eventType) {
                        case RockerView.EVENT_ACTION:
                            // 触摸事件回调
                            Log.i("EVENT_ACTION-------->", "angle=" + currentAngle + " - distance" + currentDistance);
                            if ((currentAngle >= 0 && currentAngle < 22.5) || (currentAngle < 360 && currentAngle >= 337.5)) {
                                BluetoothHelper.write("d");
                                System.out.println("d");
                            } else if (currentAngle >= 22.5 && currentAngle < 67.5) {
                                BluetoothHelper.write("e");
                                System.out.println("e");
                            } else if (currentAngle >= 67.5 && currentAngle < 112.5) {
                                BluetoothHelper.write("w");
                                System.out.println("w");
                            } else if (currentAngle >= 112.5 && currentAngle < 157.5) {
                                BluetoothHelper.write("q");
                                System.out.println("q");
                            } else if (currentAngle >= 157.5 && currentAngle < 202.5) {
                                BluetoothHelper.write("a");
                                System.out.println("a");
                            } else if (currentAngle >= 202.5 && currentAngle < 247.5) {
                                BluetoothHelper.write("z");
                                System.out.println("z");
                            } else if (currentAngle >= 247.5 && currentAngle < 292.5) {
                                BluetoothHelper.write("s");
                                System.out.println("s");
                            } else if (currentAngle >= 292.5 && currentAngle < 337.5) {
                                BluetoothHelper.write("c");
                                System.out.println("c");
                            } else {
//                            carUtil.stop();
                                BluetoothHelper.write(" ");
                                System.out.println("space");
                            }

                            break;
                        case RockerView.EVENT_CLOCK:
                            // 定时回调
//                        Log.i("EVENT_CLOCK", "angle=" + currentAngle + " - distance" + currentDistance);
                            break;
                    }
                }
            });
        }
    }
    static volatile AtomicInteger count = new AtomicInteger(0);
    @Override
    public boolean onGenericMotionEvent(MotionEvent event) {
//        if (count.incrementAndGet() < 3){
//            return super.onGenericMotionEvent(event);
//        }else {
//            count.set(0);
//        }
        // Check that the event came from a game controller
        if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) ==
                InputDevice.SOURCE_JOYSTICK &&
                event.getAction() == MotionEvent.ACTION_MOVE) {

            // Process all historical movement samples in the batch
//            final int historySize = event.getHistorySize();
//
//            // Process the movements starting from the
//            // earliest historical position in the batch
//            for (int i = 0; i < historySize; i++) {
//                // Process the event at historical position i
//                processJoystickInput(event, i);
//            }

            // Process the current movement sample in the batch (position -1)
            processJoystickInput(event, -1);
            return true;
        }
        return super.onGenericMotionEvent(event);
    }

    private void processJoystickInput(MotionEvent event,
                                      int historyPos) {

        InputDevice mInputDevice = event.getDevice();

        // Calculate the horizontal distance to move by
        // using the input value from one of these physical controls:
        // the left control stick, hat axis, or the right control stick.
        float x = getCenteredAxis(event, mInputDevice,
                MotionEvent.AXIS_X, historyPos);
        if (x == 0) {
            x = getCenteredAxis(event, mInputDevice,
                    MotionEvent.AXIS_HAT_X, historyPos);
        }
        if (x == 0) {
            x = getCenteredAxis(event, mInputDevice,
                    MotionEvent.AXIS_Z, historyPos);
        }

        // Calculate the vertical distance to move by
        // using the input value from one of these physical controls:
        // the left control stick, hat switch, or the right control stick.
        float y = getCenteredAxis(event, mInputDevice,
                MotionEvent.AXIS_Y, historyPos);
        if (y == 0) {
            y = getCenteredAxis(event, mInputDevice,
                    MotionEvent.AXIS_HAT_Y, historyPos);
        }
        if (y == 0) {
            y = getCenteredAxis(event, mInputDevice,
                    MotionEvent.AXIS_RZ, historyPos);
        }
        if ((x >= 0.75 && x <= 1) && (y < 0.25 && y > -0.25)) {
            BluetoothHelper.write("d");
            System.out.println("d");
        } else if (y < -0.75 && (x > 0.25 && x < 0.75)) {
            BluetoothHelper.write("e");
            System.out.println("e");
        } else if (x > -0.25 && x < 0.25 && y >= -1 && y < -0.75) {
            BluetoothHelper.write("w");
            System.out.println("w");
        } else if (x <= -0.25 && x > -0.75 && y <= -0.25 && x > -0.75) {
            BluetoothHelper.write("q");
            System.out.println("q");
        } else if (x >= -1 && x < -0.75 && y >= -0.25 && y < 0.25) {
            BluetoothHelper.write("a");
            System.out.println("a");
        } else if (x >= -0.75 && x < -0.25 && y >= 0.25 && y < 0.75) {
            BluetoothHelper.write("z");
            System.out.println("z");
        } else if (x >= -0.25 && x < 0.25 && y >= 0.75 && y <= 1) {
            BluetoothHelper.write("s");
            System.out.println("s");
        } else if (x >= 0.25 && x < 0.75 && y >= 0.25 && y < 0.75) {
            BluetoothHelper.write("c");
            System.out.println("c");
        }
//        else {
////                            carUtil.stop();
//            BluetoothHelper.write(" ");
//            System.out.println("space");
//        }

        // Update the ship object based on the new x and y values
    }

    private static float getCenteredAxis(MotionEvent event,
                                         InputDevice device, int axis, int historyPos) {
        final InputDevice.MotionRange range =
                device.getMotionRange(axis, event.getSource());

        // A joystick at rest does not always report an absolute position of
        // (0,0). Use the getFlat() method to determine the range of values
        // bounding the joystick axis center.
        if (range != null) {
            final float flat = range.getFlat();
            final float value =
                    historyPos < 0 ? event.getAxisValue(axis) :
                            event.getHistoricalAxisValue(axis, historyPos);

            // Ignore axis values that are within the 'flat' region of the
            // joystick axis center.
            if (Math.abs(value) > flat) {
                return value;
            }
        }
        return 0;
    }

    private static boolean isFireKey(int keyCode) {
        // Here we treat Button_A and DPAD_CENTER as the primary action
        // keys for the game.
        return keyCode == KeyEvent.KEYCODE_DPAD_CENTER
                || keyCode == KeyEvent.KEYCODE_BUTTON_A;
    }

    public ArrayList<Integer> getGameControllerIds() {
        ArrayList<Integer> gameControllerDeviceIds = new ArrayList<Integer>();
        int[] deviceIds = InputDevice.getDeviceIds();
        for (int deviceId : deviceIds) {
            InputDevice dev = InputDevice.getDevice(deviceId);
            int sources = dev.getSources();

            // Verify that the device has gamepad buttons, control sticks, or both.
            if (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
                    || ((sources & InputDevice.SOURCE_JOYSTICK)
                    == InputDevice.SOURCE_JOYSTICK)) {
                // This device is a game controller. Store its device ID.
                if (!gameControllerDeviceIds.contains(deviceId)) {
                    gameControllerDeviceIds.add(deviceId);
                }
            }
        }
        return gameControllerDeviceIds;
    }
}
